import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.InputEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Path2D;
import java.awt.geom.Path2D.Double;
import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.TreeMap;
import javax.sound.sampled.Line;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JViewport;

/**
 * 
 * @author Adam and Terry
 *
 */

public class ViewPanel extends JPanel implements MouseMotionListener,MouseListener, ItemListener, MouseWheelListener  {

	private MapFrame parent;
	private JViewport vport;
	private AffineTransform t;
	private Path2D.Double draw;	
	private double xScale;
	private double yScale;
	private MapConsole console;
	private Region region;
	private double factor;
	
	/**
	 * 
	 * @param region
	 * @param console
	 * @param parent
	 */

	public ViewPanel(Region region, MapConsole console, MapFrame parent) {
		this.parent = parent;
		this.vport = parent.getViewport();
		this.console = console;
		this.region = region;
		this.factor = 1;
		t = new AffineTransform();
		addMouseMotionListener(this);
		//addComponentListener(this);
		addMouseListener(this);
		addMouseWheelListener(this);
		console.getRail().addItemListener(this);
	    console.getRoad().addItemListener(this);
	    console.getSuburb().addItemListener(this);
	    console.getComboBox().addItemListener(this);   
	}
	
	/**
	 * 
	 */

	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2 = (Graphics2D) g;
		drawState(g2);
		drawRail(g2);
		drawRoad(g2);
		drawSuburb(g2);
		drawMarkers(g2);
	}
	
	/**
	 * 
	 * @param g2
	 */
	
	public void drawRoad(Graphics2D g2){
	
		if(console.getRoad().isSelected() == true)
		{
			for (Road a : region.getRoad().values())
			{
				if(!a.getSolid()){
					
					// set dashed stroke 
					
				}
				
				draw = new Path2D.Double();
				draw.append(a.getPathIterator(t), false);	
				g2.setColor(a.getColour());
				g2.setStroke(new BasicStroke(a.getThickness()));
				createScale();
				t.setToIdentity();
				g2.transform(t);
				g2.draw(draw);
			}	
		}

	}
	
	/**
	 * 
	 * @param g2
	 */
	public void drawRail(Graphics2D g2){
		
		if(console.getRail().isSelected() == true)
		{
			t.setToIdentity();
			draw = new Path2D.Double(); 
			
			for (Rail a : region.getRail().values()){
				draw.append(a.getPathIterator(t), false);
				g2.setColor(a.getColour());
			}
			
			createScale();
			t.setToIdentity();
			g2.transform(t);
			g2.draw(draw);
		}
	}
	
	public void drawSuburb(Graphics2D g2)
	{
		boolean noselection = true;
		if(!console.getSelectedComboValue().equalsIgnoreCase("all")){
			noselection = false;
		}
		if(console.getSuburb().isSelected() == true){
			
			t.setToIdentity();
			draw = new Path2D.Double();
		
			for (Area r : region.getArea().values()){
		
				if(noselection)
				{
					draw.append(r.getPathIterator(t), false);
					g2.setColor(r.getColour());
				}
				else
				{
					if(r.getName().equalsIgnoreCase(console.getSelectedComboValue()))
					{
						draw.append(r.getPathIterator(t), false);
						g2.setColor(r.getColour());
					}	
				}
			}
			
			createScale();
			t.setToIdentity();
			g2.transform(t);
			g2.draw(draw);
		}
			
	}
	
	/**
	 * 
	 * @param g2
	 */
	
	public void drawState(Graphics2D g2)
	{
		t.setToIdentity();
		draw = new Path2D.Double();
		
		for (State r : region.getState().values()){
			g2.setColor(r.getColour());
			draw.append(r.getPathIterator(t), false);
		}
		
		createScale();
		g2.transform(t);
		g2.draw(draw);
	}
	
	public void drawMarkers(Graphics2D g2)
	{
		t.setToIdentity();
		draw = new Path2D.Double();
		
		for (Point r : region.getPoint().values()){
			g2.setColor(r.getColour());
			draw.append(r.getPathIterator(t), false);
		}
		
		createScale();
		g2.transform(t);
		g2.draw(draw);
	}
	
	/**
	 * 
	 */
	
	public void createScale()
	{
		xScale = (double) factor*(getWidth() / draw.getBounds2D().getWidth());
		yScale = (double) factor*(getHeight() / draw.getBounds2D().getHeight());
		
		//t.setToIdentity();
		t.scale(xScale, -yScale);		
		t.translate(-draw.getBounds2D().getX(), -(draw.getBounds2D().getY()+ draw.getBounds2D().getHeight()));
	
	}
	
	/**
	 * 
	 */

	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}
	
	
	/*
	 * (non-Javadoc)
	 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
	 */

	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub
		String title = "x: " + arg0.getPoint().x + " y: " + arg0.getPoint().y;
		Point2D.Double temp = getXandYValues(arg0);
		title = title.concat(" x : " + Math.round(temp.x));
		title = title.concat(" y : " + Math.round(temp.y));
		
		parent.setTitle(title);
	}
	
	/**
	 * 
	 * @param arg0
	 * @return x and y values 
	 */
	
	public Point2D.Double getXandYValues(MouseEvent arg0)
	{
		Point2D.Double temp = new Point2D.Double();
		
		try {
			AffineTransform inv = t.createInverse();
			
		} catch (NoninvertibleTransformException e) {
			// TODO Auto-generated catch block
			System.out.println(e.getMessage());
		}
		
		return temp;	
	}

	/**
	 * 
	 */
	public void itemStateChanged(ItemEvent e) {
		// checkbox checked or select box value changed 
		this.repaint();
	    
	}
	
	/**
	 * 
	 */

	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * 
	 */

	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * 
	 */

	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	/**
	 * 
	 */
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
		Point2D.Double pointxy = getXandYValues(arg0);
		String name = showDialogBox();
		Point point = new Point(name, pointxy);
		region.addPointObject(point);
	}
	
	/**
	 * 
	 */

	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	/**
	 * 
	 */
	public String showDialogBox()
	{
		 String str = JOptionPane.showInputDialog(null, "Please Enter Name : ",  "", 1);
		 return str; 
	}
	
	/**
	 * 
	 */

	public void mouseWheelMoved(MouseWheelEvent arg0) {
		// TODO Auto-generated method stub
		if (arg0.getWheelRotation() < 0) {
			factor *= 2;
			repaint();
			vport.setViewPosition(arg0.getPoint());
		}
		else if (arg0.getWheelRotation() > 0) {
			factor /= 2;
			repaint();
			vport.setViewPosition(arg0.getPoint());			
		}
	}
}
